{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g_nWetWWd_ns"
      },
      "source": [
        "##### Copyright 2021 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "2pHVBk_seED1"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M7vSdG6sAIQn"
      },
      "source": [
        "# On-Device Training with TensorFlow Lite"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fwc5GKHBASdc"
      },
      "source": [
        "\u003ctable class=\"tfo-notebook-buttons\" align=\"left\"\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://www.tensorflow.org/lite/examples/on_device_training/overview\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" /\u003eView on TensorFlow.org\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/examples/on_device_training/overview.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" /\u003eRun in Google Colab\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/g3doc/examples/on_device_training/overview.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" /\u003eView source on GitHub\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca href=\"https://storage.googleapis.com/tensorflow_docs/tensorflow/tensorflow/lite/g3doc/examples/on_device_training/overview.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/download_logo_32px.png\" /\u003eDownload notebook\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "\u003c/table\u003e"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9ee074e4"
      },
      "source": [
        "When deploying TensorFlow Lite machine learning model to device or mobile app, you may want to enable the model to be improved or personalized based on input from the device or end user. Using on-device training techniques allows you to update a model *without* data leaving your users' devices, improving user privacy, and without requiring users to update the device software.\n",
        "\n",
        "For example, you may have a model in your mobile app that recognizes fashion items, but you want users to get improved recognition performance over time based on their interests. Enabling on-device training allows users who are interested in shoes to get better at recognizing a particular style of shoe or shoe brand the more often they use your app.\n",
        "\n",
        "This tutorial shows you how to construct a TensorFlow Lite model that can be incrementally trained and improved within an installed Android app.\n",
        "\n",
        "Note: The on-device training technique can be added to existing TensorFlow Lite implementations, provided the devices you are targeting support local file storage.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UaWdLA3fQDK2"
      },
      "source": [
        "## Setup\n",
        "\n",
        "This tutorial uses Python to train and convert a TensorFlow model before incorporating it into an Android app. Get started by installing and importing the following packages."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9j4MGqyKQEo4"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "TensorFlow version: 2.8.0\n"
          ]
        }
      ],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "\n",
        "print(\"TensorFlow version:\", tf.__version__)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oOCyq3dTvfL6"
      },
      "source": [
        "Note: The On-Device Training APIs are available in TensorFlow version 2.7 and higher."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_omifE5JKpt4"
      },
      "source": [
        "## Classify images of clothing\n",
        "\n",
        "This example code uses the [Fashion MNIST dataset](https://keras.io/api/datasets/fashion_mnist/) to train a neural network model for classifying images of clothing. This dataset contains 60,000 small (28 x 28 pixel) grayscale images containing 10 different categories of fashion accessories, including dresses, shirts, and sandals.\n",
        "\n",
        "\u003cfigure\u003e\n",
        "  \u003cimg src=\"https://tensorflow.org/images/fashion-mnist-sprite.png\"\n",
        "       alt=\"Fashion MNIST images\"\u003e\n",
        "  \u003cfigcaption\u003e\u003cb\u003eFigure 1\u003c/b\u003e: \u003ca href=\"https://github.com/zalandoresearch/fashion-mnist\"\u003eFashion-MNIST samples\u003c/a\u003e (by Zalando, MIT License).\u003c/figcaption\u003e\n",
        "\u003c/figure\u003e\n",
        "\n",
        "You can explore this dataset in more depth in the [Keras classification tutorial](https://www.tensorflow.org/tutorials/keras/classification#import_the_fashion_mnist_dataset)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FN2N6hPEP-Ay"
      },
      "source": [
        "## Build a model for on-device training\n",
        "\n",
        "TensorFlow Lite models typically have only a single exposed function method (or [signature](https://www.tensorflow.org/lite/guide/signatures)) that allows you to call the model to run an inference. For a model to be trained and used on a device, you must be able to perform several separate operations, including train, infer, save, and restore functions for the model. You can enable this functionality by first extending your TensorFlow model to have multiple functions, and then exposing those functions as signatures when you convert your model to the TensorFlow Lite model format.\n",
        "\n",
        "The code example below shows you how to add the following functions to a TensorFlow model:\n",
        "\n",
        "*   `train` function trains the model with training data.\n",
        "*   `infer` function invokes the inference.\n",
        "*   `save` function saves the trainable weights into the file system.\n",
        "*   `restore` function loads the trainable weights from the file system."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d8577c80"
      },
      "outputs": [],
      "source": [
        "IMG_SIZE = 28\n",
        "\n",
        "class Model(tf.Module):\n",
        "\n",
        "  def __init__(self):\n",
        "    self.model = tf.keras.Sequential([\n",
        "        tf.keras.layers.Flatten(input_shape=(IMG_SIZE, IMG_SIZE), name='flatten'),\n",
        "        tf.keras.layers.Dense(128, activation='relu', name='dense_1'),\n",
        "        tf.keras.layers.Dense(10, name='dense_2')\n",
        "    ])\n",
        "\n",
        "    self.model.compile(\n",
        "        optimizer='sgd',\n",
        "        loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True))\n",
        "\n",
        "  # The `train` function takes a batch of input images and labels.\n",
        "  @tf.function(input_signature=[\n",
        "      tf.TensorSpec([None, IMG_SIZE, IMG_SIZE], tf.float32),\n",
        "      tf.TensorSpec([None, 10], tf.float32),\n",
        "  ])\n",
        "  def train(self, x, y):\n",
        "    with tf.GradientTape() as tape:\n",
        "      prediction = self.model(x)\n",
        "      loss = self.model.loss(y, prediction)\n",
        "    gradients = tape.gradient(loss, self.model.trainable_variables)\n",
        "    self.model.optimizer.apply_gradients(\n",
        "        zip(gradients, self.model.trainable_variables))\n",
        "    result = {\"loss\": loss}\n",
        "    return result\n",
        "\n",
        "  @tf.function(input_signature=[\n",
        "      tf.TensorSpec([None, IMG_SIZE, IMG_SIZE], tf.float32),\n",
        "  ])\n",
        "  def infer(self, x):\n",
        "    logits = self.model(x)\n",
        "    probabilities = tf.nn.softmax(logits, axis=-1)\n",
        "    return {\n",
        "        \"output\": probabilities,\n",
        "        \"logits\": logits\n",
        "    }\n",
        "\n",
        "  @tf.function(input_signature=[tf.TensorSpec(shape=[], dtype=tf.string)])\n",
        "  def save(self, checkpoint_path):\n",
        "    tensor_names = [weight.name for weight in self.model.weights]\n",
        "    tensors_to_save = [weight.read_value() for weight in self.model.weights]\n",
        "    tf.raw_ops.Save(\n",
        "        filename=checkpoint_path, tensor_names=tensor_names,\n",
        "        data=tensors_to_save, name='save')\n",
        "    return {\n",
        "        \"checkpoint_path\": checkpoint_path\n",
        "    }\n",
        "\n",
        "  @tf.function(input_signature=[tf.TensorSpec(shape=[], dtype=tf.string)])\n",
        "  def restore(self, checkpoint_path):\n",
        "    restored_tensors = {}\n",
        "    for var in self.model.weights:\n",
        "      restored = tf.raw_ops.Restore(\n",
        "          file_pattern=checkpoint_path, tensor_name=var.name, dt=var.dtype,\n",
        "          name='restore')\n",
        "      var.assign(restored)\n",
        "      restored_tensors[var.name] = restored\n",
        "    return restored_tensors"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "86tBMjoBnp6d"
      },
      "source": [
        "The `train` function in the code above uses the [GradientTape](https://www.tensorflow.org/api_docs/python/tf/GradientTape) class to record operations for automatic differentiation. For more information on how to use this class, see the [Introduction to gradients and automatic differentiation](https://www.tensorflow.org/guide/autodiff).\n",
        "\n",
        "You could use the `Model.train_step` method of the keras model here instead of a from-scratch implementation. Just note that the loss (and metrics) returned by `Model.train_step` is the running average, and should be reset regularly (typically each epoch). See [Customize Model.fit](https://www.tensorflow.org/guide/keras/customizing_what_happens_in_fit) for details.\n",
        "\n",
        "Note: The weights generated by this model are serialized into a TensorFlow 1 format checkpoint file."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "a813419961ef"
      },
      "source": [
        "## Prepare the data\n",
        "\n",
        "Get the the Fashion MNIST dataset for training your model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "315b8b4dfc16"
      },
      "outputs": [],
      "source": [
        "fashion_mnist = tf.keras.datasets.fashion_mnist\n",
        "(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2eDn-bRD30sw"
      },
      "source": [
        "### Preprocess the dataset\n",
        "\n",
        "Pixel values in this dataset are between 0 and 255, and must be normalized to a value between 0 and 1 for processing by the model. Divide the values by 255 to make this adjustment."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "g0FqHC0yCg6n"
      },
      "outputs": [],
      "source": [
        "train_images = (train_images / 255.0).astype(np.float32)\n",
        "test_images = (test_images / 255.0).astype(np.float32)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1bbee849ab73"
      },
      "source": [
        "Convert the data labels to categorical values by performing one-hot encoding."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Fmc7EgYO30sw"
      },
      "outputs": [],
      "source": [
        "train_labels = tf.keras.utils.to_categorical(train_labels)\n",
        "test_labels = tf.keras.utils.to_categorical(test_labels)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "79f5f372fb0e"
      },
      "source": [
        "Note: Make sure you preprocess your *training* and *testing* datasets in the same way, so that your testing accurately evaluate your model's performance."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xkuDUFNNyAVN"
      },
      "source": [
        "## Train the model\n",
        "\n",
        "Before converting and setting up your TensorFlow Lite model, complete the initial training of your model using the preprocessed dataset and the `train` signature method. The following code runs model training for 100 epochs, processing batches of 100 images at a time, and displaying the loss value after every 10 epochs. Since this training run is processing quite a bit of data, it may take a few minutes to finish.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Diwn1MmkNVeX"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Finished 10 epochs\n",
            "  loss: 0.428\n",
            "Finished 20 epochs\n",
            "  loss: 0.378\n",
            "Finished 30 epochs\n",
            "  loss: 0.344\n",
            "Finished 40 epochs\n",
            "  loss: 0.317\n",
            "Finished 50 epochs\n",
            "  loss: 0.299\n",
            "Finished 60 epochs\n",
            "  loss: 0.283\n",
            "Finished 70 epochs\n",
            "  loss: 0.266\n",
            "Finished 80 epochs\n",
            "  loss: 0.252\n",
            "Finished 90 epochs\n",
            "  loss: 0.240\n",
            "Finished 100 epochs\n",
            "  loss: 0.230\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "{'checkpoint_path': \u003ctf.Tensor: shape=(), dtype=string, numpy=b'/tmp/model.ckpt'\u003e}"
            ]
          },
          "execution_count": 28,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "NUM_EPOCHS = 100\n",
        "BATCH_SIZE = 100\n",
        "epochs = np.arange(1, NUM_EPOCHS + 1, 1)\n",
        "losses = np.zeros([NUM_EPOCHS])\n",
        "m = Model()\n",
        "\n",
        "train_ds = tf.data.Dataset.from_tensor_slices((train_images, train_labels))\n",
        "train_ds = train_ds.batch(BATCH_SIZE)\n",
        "\n",
        "for i in range(NUM_EPOCHS):\n",
        "  for x,y in train_ds:\n",
        "    result = m.train(x, y)\n",
        "\n",
        "  losses[i] = result['loss']\n",
        "  if (i + 1) % 10 == 0:\n",
        "    print(f\"Finished {i+1} epochs\")\n",
        "    print(f\"  loss: {losses[i]:.3f}\")\n",
        "\n",
        "# Save the trained weights to a checkpoint.\n",
        "m.save('/tmp/model.ckpt')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Lp2nkZj7rJXm"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\nrkJggg==\n",
            "text/plain": [
              "\u003cFigure size 600x400 with 1 Axes\u003e"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(epochs, losses, label='Pre-training')\n",
        "plt.ylim([0, max(plt.ylim())])\n",
        "plt.xlabel('Epoch')\n",
        "plt.ylabel('Loss [Cross Entropy]')\n",
        "plt.legend();"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LaMMDLLewAaX"
      },
      "source": [
        "Note: You should complete initial training of your model before converting it to TensorFlow Lite format, so that the model has an initial set of weights, and is able to perform reasonable inferences *before* you start collecting data and conducting training runs on the device."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A8YUTIvzMVw5"
      },
      "source": [
        "## Convert model to TensorFlow Lite format\n",
        "\n",
        "After you have extended your TensorFlow model to enable additional functions for on-device training and completed initial training of the model, you can convert it to TensorFlow Lite format. The following code converts and saves your model to that format, including the set of signatures that you use with the TensorFlow Lite model on a device: `train, infer, save, restore`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "WwsDUEKFMYtq"
      },
      "outputs": [],
      "source": [
        "SAVED_MODEL_DIR = \"saved_model\"\n",
        "\n",
        "tf.saved_model.save(\n",
        "    m,\n",
        "    SAVED_MODEL_DIR,\n",
        "    signatures={\n",
        "        'train':\n",
        "            m.train.get_concrete_function(),\n",
        "        'infer':\n",
        "            m.infer.get_concrete_function(),\n",
        "        'save':\n",
        "            m.save.get_concrete_function(),\n",
        "        'restore':\n",
        "            m.restore.get_concrete_function(),\n",
        "    })\n",
        "\n",
        "# Convert the model\n",
        "converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_DIR)\n",
        "converter.target_spec.supported_ops = [\n",
        "    tf.lite.OpsSet.TFLITE_BUILTINS,  # enable TensorFlow Lite ops.\n",
        "    tf.lite.OpsSet.SELECT_TF_OPS  # enable TensorFlow ops.\n",
        "]\n",
        "converter.experimental_enable_resource_variables = True\n",
        "tflite_model = converter.convert()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GJSOtPISKSn2"
      },
      "source": [
        "### Setup the TensorFlow Lite signatures\n",
        "\n",
        "The TensorFlow Lite model you saved in the previous step contains several function signatures. You can access them through the `tf.lite.Interpreter` class and invoke each `restore`, `train`, `save`, and `infer` signature separately."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qNX2vqXd2-HM"
      },
      "outputs": [],
      "source": [
        "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n",
        "interpreter.allocate_tensors()\n",
        "\n",
        "infer = interpreter.get_signature_runner(\"infer\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vTOM4alkteTO"
      },
      "source": [
        "Compare the output of the original model, and the converted lite model:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IDdaCmPEtE7P"
      },
      "outputs": [],
      "source": [
        "logits_original = m.infer(x=train_images[:1])['logits'][0]\n",
        "logits_lite = infer(x=train_images[:1])['logits'][0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IpoZ1nTMKGEZ"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "\u003cFigure size 600x400 with 1 Axes\u003e"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "#@title\n",
        "def compare_logits(logits):\n",
        "  width = 0.35\n",
        "  offset = width/2\n",
        "  assert len(logits)==2\n",
        "\n",
        "  keys = list(logits.keys())\n",
        "  plt.bar(x = np.arange(len(logits[keys[0]]))-offset,\n",
        "      height=logits[keys[0]], width=0.35, label=keys[0])\n",
        "  plt.bar(x = np.arange(len(logits[keys[1]]))+offset,\n",
        "      height=logits[keys[1]], width=0.35, label=keys[1])\n",
        "  plt.legend()\n",
        "  plt.grid(True)\n",
        "  plt.ylabel('Logit')\n",
        "  plt.xlabel('ClassID')\n",
        "\n",
        "  delta = np.sum(np.abs(logits[keys[0]] - logits[keys[1]]))\n",
        "  plt.title(f\"Total difference: {delta:.3g}\")\n",
        "\n",
        "compare_logits({'Original': logits_original, 'Lite': logits_lite})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ARUb37Hqa0Az"
      },
      "source": [
        "Above, you can see that the behavior of the model is not changed by the conversion to TFLite."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7a5f73c8c5d6"
      },
      "source": [
        "## Retrain the model on a device\n",
        "\n",
        "After converting your model to TensorFlow Lite and deploying it with your app, you can retrain the model on a device using new data and the `train` signature method of your model. Each training run generates a new set of weights that you can save for re-use and further improvement of the model, as shown in the next section.\n",
        "\n",
        "Note: Since training tasks are resource intensive, you should consider performing them when users are not actively interacting with the device, and as a background process. Consider using the [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) API to schedule model retraining as an asynchronous task.\n",
        "\n",
        "On Android, you can perform on-device training with TensorFlow Lite using either Java or C++ APIs. In Java, use the `Interpreter` class to load a model and drive model training tasks. The following example shows how to run the training procedure using the `runSignature` method:\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qvbqRxnNs4NG"
      },
      "source": [
        "```Java\n",
        "try (Interpreter interpreter = new Interpreter(modelBuffer)) {\n",
        "    int NUM_EPOCHS = 100;\n",
        "    int BATCH_SIZE = 100;\n",
        "    int IMG_HEIGHT = 28;\n",
        "    int IMG_WIDTH = 28;\n",
        "    int NUM_TRAININGS = 60000;\n",
        "    int NUM_BATCHES = NUM_TRAININGS / BATCH_SIZE;\n",
        "\n",
        "    List\u003cFloatBuffer\u003e trainImageBatches = new ArrayList\u003c\u003e(NUM_BATCHES);\n",
        "    List\u003cFloatBuffer\u003e trainLabelBatches = new ArrayList\u003c\u003e(NUM_BATCHES);\n",
        "\n",
        "    // Prepare training batches.\n",
        "    for (int i = 0; i \u003c NUM_BATCHES; ++i) {\n",
        "        FloatBuffer trainImages = FloatBuffer.allocateDirect(BATCH_SIZE * IMG_HEIGHT * IMG_WIDTH).order(ByteOrder.nativeOrder());\n",
        "        FloatBuffer trainLabels = FloatBuffer.allocateDirect(BATCH_SIZE * 10).order(ByteOrder.nativeOrder());\n",
        "\n",
        "        // Fill the data values...\n",
        "        trainImageBatches.add(trainImages.rewind());\n",
        "        trainImageLabels.add(trainLabels.rewind());\n",
        "    }\n",
        "\n",
        "    // Run training for a few steps.\n",
        "    float[] losses = new float[NUM_EPOCHS];\n",
        "    for (int epoch = 0; epoch \u003c NUM_EPOCHS; ++epoch) {\n",
        "        for (int batchIdx = 0; batchIdx \u003c NUM_BATCHES; ++batchIdx) {\n",
        "            Map\u003cString, Object\u003e inputs = new HashMap\u003c\u003e();\n",
        "            inputs.put(\"x\", trainImageBatches.get(batchIdx));\n",
        "            inputs.put(\"y\", trainLabelBatches.get(batchIdx));\n",
        "\n",
        "            Map\u003cString, Object\u003e outputs = new HashMap\u003c\u003e();\n",
        "            FloatBuffer loss = FloatBuffer.allocate(1);\n",
        "            outputs.put(\"loss\", loss);\n",
        "\n",
        "            interpreter.runSignature(inputs, outputs, \"train\");\n",
        "\n",
        "            // Record the last loss.\n",
        "            if (batchIdx == NUM_BATCHES - 1) losses[epoch] = loss.get(0);\n",
        "        }\n",
        "\n",
        "        // Print the loss output for every 10 epochs.\n",
        "        if ((epoch + 1) % 10 == 0) {\n",
        "            System.out.println(\n",
        "              \"Finished \" + (epoch + 1) + \" epochs, current loss: \" + loss.get(0));\n",
        "        }\n",
        "    }\n",
        "\n",
        "    // ...\n",
        "}\n",
        "```\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cPEzyHAZs7Gl"
      },
      "source": [
        "You can see a complete code example of model retraining inside an Android app in the [model personalization demo app](https://github.com/tensorflow/examples/blob/master/lite/examples/model_personalization/android/transfer_api/src/main/java/org/tensorflow/lite/examples/transfer/api/LiteMultipleSignatureModel.java)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HuBlL9z5GASQ"
      },
      "source": [
        "Run training for a few epochs to improve or personalize the model. In practice, you would run this additional training using data collected on the device. For simplicity, this example uses the same training data as the previous training step."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pjQ5xrhyGcIQ"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Finished 10 epochs\n",
            "  loss: 0.223\n",
            "Finished 20 epochs\n",
            "  loss: 0.216\n",
            "Finished 30 epochs\n",
            "  loss: 0.210\n",
            "Finished 40 epochs\n",
            "  loss: 0.204\n",
            "Finished 50 epochs\n",
            "  loss: 0.198\n"
          ]
        }
      ],
      "source": [
        "train = interpreter.get_signature_runner(\"train\")\n",
        "\n",
        "NUM_EPOCHS = 50\n",
        "BATCH_SIZE = 100\n",
        "more_epochs = np.arange(epochs[-1]+1, epochs[-1] + NUM_EPOCHS + 1, 1)\n",
        "more_losses = np.zeros([NUM_EPOCHS])\n",
        "\n",
        "\n",
        "for i in range(NUM_EPOCHS):\n",
        "  for x,y in train_ds:\n",
        "    result = train(x=x, y=y)\n",
        "  more_losses[i] = result['loss']\n",
        "  if (i + 1) % 10 == 0:\n",
        "    print(f\"Finished {i+1} epochs\")\n",
        "    print(f\"  loss: {more_losses[i]:.3f}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vX7dQXx_iPuv"
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEHCAYAAACjh0HiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90\nbGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsT\nAAALEwEAmpwYAAAuJklEQVR4nO3deXxU5dn/8c9FCAkJSYCwE5aALEZ2Aiii4gouxaWiqK21tbXa\nR+1qaxdb/XXz0fZprXUp7rZ9aq1baev21LWKKCCLgAIhoAQChABZCAlJuH5/nEkMIQlDksmEzPf9\nes0rc5Y5cyWQfOe+73PuY+6OiIjErk7RLkBERKJLQSAiEuMUBCIiMU5BICIS4xQEIiIxTkEgIhLj\nOkfy4GY2G7gLiAMedPfb622/CbiiTi3HAr3dfVdjx+zVq5cPHTo0MgWLiHRQS5cu3enuvRvaZpG6\njsDM4oB1wJlAHrAYuMzd1zSy/2eAb7r7aU0dNzs725csWdLa5YqIdGhmttTdsxvaFsmuoalAjrvn\nuvt+4Ang/Cb2vwz4SwTrERGRBkQyCAYCm+ss54XWHcLMkoDZwNONbL/GzJaY2ZKCgoJWL1REJJZF\nMgisgXWN9UN9Bni7sbEBd5/v7tnunt27d4NdXCIi0kyRHCzOAwbVWc4Atjay7zzULSTS4VRWVpKX\nl0d5eXm0S4kZiYmJZGRkEB8fH/ZrIhkEi4ERZpYJbCH4Y395/Z3MLA04BfhcBGsRkSjIy8sjJSWF\noUOHYtZQJ4G0JnensLCQvLw8MjMzw35dxLqG3L0KuB54CfgQeNLdV5vZtWZ2bZ1dLwRedve9kaoF\n4MVV2xj7k5fILSiN5NuISB3l5eWkp6crBNqImZGenn7ELbCIXkfg7s8Dz9dbd3+95UeBRyNZB0B8\nnFFSUUVJeVWk30pE6lAItK3m/Lxj5sribglB5pVWKAhEROqKmSBISQwGTtQiEIkdcXFxTJgwgTFj\nxjB37lzKysqafaznnnuONWsavB62SQsWLOD2229vcp+tW7dy8cUXN7e0FouhIAhaBCXllVGuRETa\nSteuXVm+fDmrVq2iS5cu3H//QT3TVFdXh32spoKgqqrxD5hz5szh5ptvbvLYAwYM4Kmnngq7ltYW\nM0GgriGR2HbSSSeRk5PD66+/zqmnnsrll1/O2LFjqa6u5qabbmLKlCmMGzeOP/zhD4e8duHChSxY\nsICbbrqJCRMmsGHDBmbOnMkPfvADTjnlFO666y7+8Y9/MG3aNCZOnMgZZ5zB9u3bAXj00Ue5/vrr\nAbjqqqu48cYbmT59OsOGDav9479p0ybGjBlTu/9FF13E7NmzGTFiBN/97ndr63jooYcYOXIkM2fO\n5Ctf+UrtcVsqooPF7Um3UIugVF1DIlFx2z9Ws2ZrcaseM2tAKj/5zHGH3a+qqooXXniB2bNnA/De\ne++xatUqMjMzmT9/PmlpaSxevJiKigpOPPFEzjrrrINOv5w+fTpz5szhvPPOO6gLZ8+ePbzxxhsA\n7N69m0WLFmFmPPjgg9xxxx38+te/PqSW/Px83nrrLT766CPmzJnTYJfQ8uXLWbZsGQkJCYwaNYob\nbriBuLg4fvrTn/L++++TkpLCaaedxvjx44/4Z9aQmAmC+LhOJMZ3okQtApGYsW/fPiZMmAAELYKr\nr76ahQsXMnXq1No/9C+//DIrV66s/XReVFTE+vXrwzoP/9JLL619npeXx6WXXkp+fj779+9v9PUX\nXHABnTp1Iisrq7bVUN/pp59OWloaAFlZWXz88cfs3LmTU045hZ49ewIwd+5c1q1bF94P4jBiJggA\nuiXEa7BYJErC+eTe2mrGCOpLTk6ufe7u3H333cyaNeugfX74wx/yr3/9C6DBY9Q/zg033MC3vvUt\n5syZw+uvv86tt97a4GsSEhIOeu/D7RMXF0dVVVWj+7aGmBkjAEhN7KwxAhE5yKxZs7jvvvuorAxO\nJFm3bh179+7l5z//OcuXL68NgZSUFEpKSho9TlFREQMHBvNqPvbYY61e59SpU3njjTfYvXs3VVVV\nPP10g3N0NktMBUG3xM6U6qwhEanjy1/+MllZWUyaNIkxY8bw1a9+tcGzgObNm8edd97JxIkT2bBh\nwyHbb731VubOnctJJ51Er169Wr3OgQMH8oMf/IBp06ZxxhlnkJWVVdt91FIRuzFNpLTkxjSXP7CI\n/VUHeOq66a1clYg05MMPP+TYY4+NdhkdRmlpKd26daOqqooLL7yQL33pS1x44YWH7NfQzz1aN6Zp\nd1LUNSQiR7Fbb7219gK5zMxMLrjgglY5rgaLRUSOEr/61a8ictyYaxHoymIRkYPFVBB0Swi6ho62\ncRERkUiKqSBISezMAYd9leHPLyIi0tHFVBB0q514TuMEIiI1YisIEhQEIrEmLy+P888/nxEjRjB8\n+HC+/vWvs3///mYf7/XXX+e8885r1mvDmZI6GmIqCFJD9yTQKaQiscHdueiii7jgggtYv34969at\no7S0lB/+8IdRqSecKamjIaaCQDOQisSWV199lcTERL74xS8Cwbw9v/nNb3j44YcpKytrcsrnul58\n8UVGjx7NjBkzeOaZZ2rX7927ly996UtMmTKFiRMn8ve//x2AadOmsXr16tr9Zs6cydKlSw+aknr7\n9u1ceOGFjB8/nvHjx7Nw4UIA/vSnPzF16lQmTJjAV7/61SO6Z0Jzxdh1BLo5jUjUvHAzbPugdY/Z\nbyyc3XhXy+rVq5k8efJB61JTUxk8eDA5OTlAw1M+Dxo0qHb/8vJyvvKVr/Dqq69yzDHHHDTj6M9/\n/nNOO+00Hn74Yfbs2cPUqVM544wzmDdvHk8++SS33XYb+fn5bN26lcmTJ/PBB59+/zfeeCOnnHIK\nzz77LNXV1ZSWlvLhhx/y17/+lbfffpv4+Hi+9rWv8ec//5krr7yytX5iDYqpFkHtXcrUNSQSE9y9\nwZu5111fM+VzYmJi7ZTPdX300UdkZmYyYsQIzIzPfe5ztdtefvllbr/9diZMmMDMmTMpLy/nk08+\n4ZJLLuFvf/sbAE8++SRz5849pIZXX32V6667DghaKmlpabzyyissXbqUKVOmMGHCBF555RVyc3Nb\n7efRmJhqEaQkhMYI1DUk0vaa+OQeKccdd9whs3QWFxezefNmhg8fztKlSxuc8rm+hsIEgkB5+umn\nGTVq1CHb0tPTWblyJX/9618bvOtZY8f7whe+wC9/+cuw9m8tEW0RmNlsM1trZjlm1uAIiZnNNLPl\nZrbazN6IZD3JCXGAzhoSiRWnn346ZWVlPP7440Bwj+Jvf/vbXHXVVSQlJYV1jNGjR7Nx48baGUf/\n8pe/1G6bNWsWd999d+1FqsuWLavdNm/ePO644w6KiooYO3Zsg7Xdd999tXUVFxdz+umn89RTT7Fj\nxw4Adu3adUgLJRIiFgRmFgfcA5wNZAGXmVlWvX26A/cCc9z9OODQ9lMr6hzXia7xcZRWaIxAJBaY\nGc8++yx/+9vfGDFiBCNHjiQxMZFf/OIXYR8jMTGR+fPnc+655zJjxgyGDBlSu+2WW26hsrKScePG\nMWbMGG655ZbabRdffDFPPPEEl1xySYPHveuuu3jttdcYO3YskydPZvXq1WRlZfGzn/2Ms846i3Hj\nxnHmmWeSn5/f/B9AmCI2DbWZnQDc6u6zQsvfB3D3X9bZ52vAAHf/UbjHbck01ABTf/5vTj+2D7+8\naFyzjyEi4dE01NHRnqahHghsrrOcF1pX10igh5m9bmZLzazBoXEzu8bMlpjZkoKCghYV1S2xM8Xq\nGhIRqRXJIGhodKV+86MzMBk4F5gF3GJmIw95kft8d8929+zevXu3qKiUhM4aLBYRqSOSZw3lAYPq\nLGcAWxvYZ6e77wX2mtmbwHhgXaSKSkmM15XFIm2osVM4JTKa090fyRbBYmCEmWWaWRdgHrCg3j5/\nB04ys85mlgRMAz6MYE3BVNRqEYi0icTERAoLCzX1extxdwoLC0lMTDyi10WsReDuVWZ2PfASEAc8\n7O6rzeza0Pb73f1DM3sRWAkcAB5091WRqgmCMQJdWSzSNjIyMsjLy6OlY3sSvsTERDIyMo7oNRG9\noMzdnweer7fu/nrLdwJ3RrKOulISO+vKYpE2Eh8fT2ZmZrTLkMOIqSkmIDRYrLuUiYjUirkg6JbY\nGXfYu193KRMRgRgMgpREzTckIlJXzAVBzVTUmmZCRCQQc0GQ1jVoEezaqyAQEYEYDILBPYMZBz8u\n3BvlSkRE2oeYC4KBPboS18n4ZFdZtEsREWkXYi4I4uM6MbB7VzYVKghERCAGgwBgSHqSuoZEREJi\nMgiGpiezaaeCQEQEYjQIhqQnUVxexZ6y/dEuRUQk6mI0CJIBNE4gIkKMBsHQdJ1CKiJSIyaDYFDP\nJMxg0061CEREYjIIEuPj6JeayMe71CIQEYnJIICaU0jVIhARidkgGJqerDECERFiOAiGpCezs3S/\nbmQvIjEvhoMgOHNIF5aJSKyL2SAY3S8FgJV5RVGuREQkumI2CDJ7JdMnJYFFuYXRLkVEJKo6N7bB\nzIoP81oD8t19ZOuW1DbMjBOGp7NwQyHujplFuyQRkahoqkWwwd1Tm3ikAE12sJvZbDNba2Y5ZnZz\nA9tnmlmRmS0PPX7c0m/oSBw/LJ2CkgpyNU4gIjGs0RYB8NkwXt/oPmYWB9wDnAnkAYvNbIG7r6m3\n63/c/bww3qvVHT8sHYBFuYUM790tGiWIiERdoy0Cd88FMLPrzaxHU/s0YiqQ4+657r4feAI4vyXF\ntrah6Un0S01kUe6uaJciIhI14QwW9yP4NP9kqKsn3M70gcDmOst5oXX1nWBmK8zsBTM7rqEDmdk1\nZrbEzJYUFBSE+faHZ2YcP6wn74TGCUREYtFhg8DdfwSMAB4CrgLWm9kvzGz4YV7aUGDU/2v7PjDE\n3ccDdwPPNVLDfHfPdvfs3r17H67kI3L8sHR2llawoaC0VY8rInK0COv0UQ8+Lm8LPaqAHsBTZnZH\nEy/LAwbVWc4AttY7brG7l4aePw/Em1mv8MtvuRkjgrd7cdW2tnxbEZF247BBYGY3mtlS4A7gbWCs\nu18HTKbpAeXFwAgzyzSzLsA8YEG9Y/er6Woys6mhetr0xP6MHkkcP6wnTy3NU/eQiMSkcFoEvYCL\n3H2Wu//N3SsB3P0A0OjZPu5eBVwPvAR8CDzp7qvN7Fozuza028XAKjNbAfwOmOdR+Gs8d/IgNhWW\nsXjT7rZ+axGRqLNw/u6a2SRgBkEf/9vu/n6kC2tMdna2L1mypFWPWba/iik/+zfnjO3PnXPHt+qx\nRUTaAzNb6u7ZDW0Lp2voFuAxIJ2gdfCImf2odUuMrqQunTl3XH/+9UE+ezUbqYjEmHC6hi4Hprj7\nT9z9J8DxwBWRLavtXZI9iLL91Tz9fl60SxERaVPhBMEmILHOcgKwISLVRNHkIT2YMrQHv381h337\nq6NdjohImwknCCqA1Wb2qJk9AqwCSs3sd2b2u8iW13bMjJtmjWZHSQV/XLQp2uWIiLSZpuYaqvFs\n6FHj9ciUEn1TM3ty8sje3Pv6Bi6bOpiUxPholyQiEnGHDQJ3fyx0HUDNdNNra04h7YhuOmsUn/n9\nW9z17/X86LysaJcjIhJx4Zw1NBNYTzCT6L3AOjM7ObJlRc/YjDQunzaYh9/eyIrNe6JdjohIxIUz\nRvBr4Cx3P8XdTwZmAb+JbFnRdfPZo+mdksD3nl7J/qoD0S5HRCSiwgmCeHdfW7Pg7uuADt15npoY\nz88uGMtH20r47b/XRbscEZGICicIlprZQ6G7ic00sweApZEuLNrOzOrLvCmDuPf1Dbz60fZolyMi\nEjHhBMG1wGrgRuDrwJrQug7v1jnHkdU/lW/+dQWbd5VFuxwRkYhoMgjMrBOw1N3/x90vcvcL3f03\n7l7RRvVFVWJ8HPd9bhLuzlWPvMfuvfujXZKISKtrMghCM4yuMLPBbVRPuzMkPZkHrsxm8+59XP3Y\nYl11LCIdTjhdQ/0Jrix+xcwW1DwiXVh7Mm1YOnddOoFlm/dwzR+XUF6pMBCRjiOcK4tvi3gVR4Gz\nx/bnvy8ax/eeWclXHl/CA1dmkxgfF+2yRERaLJwWwTnu/kbdB3BOpAtrjy6ZMoj/vmgcb+Xs5Jo/\nLqWiSi0DETn6hRMEZzaw7uzWLuRoccmUQdx+0VjeXFfADf+7jMpqXXAmIke3RoPAzK4zsw+AUWa2\nss5jI/BB25XY/lw6ZTC3fiaLl9ds58a/LFPLQESOak2NEfwv8ALwS+DmOutL3H1XRKs6Clx1YibV\nDj/95xqKHlnM/Cuz6ZYQzpCLiEj70miLwN2L3H2Tu18G5AGVBPcs7hbLp5PWdfWMTH49dzzvbtzF\nFQ++S9G+Djspq4h0YOHMPno9sB34P+Bfocc/I1zXUeOzkzO474pJrNlaxOcfepeiMoWBiBxdwhks\n/gYwyt2Pc/exoce4cA5uZrPNbK2Z5ZjZzU3sN8XMqs3s4jDrblfOOq4f939uMh/ll3Dp/HfYXlwe\n7ZJERMIWThBsBoqO9MBmFkdwD4OzgSzgMjM75E4vof3+G3jpSN+jPTn92L48dFU2m3eVcdG9C9lQ\nUBrtkkREwhJOEOQCr5vZ983sWzWPMF43Fchx91x33w88AZzfwH43AE8DO8Kuup06aURvnrjmBCqq\nqrngnrc1a6mIHBXCCYJPCMYHugApdR6HM5CgNVEjL7SulpkNBC4E7m/qQGZ2jZktMbMlBQUFYbx1\n9IzNSOPZr53I4J5JfOnRJfzqpbW6uY2ItGvh3LP4kCkmzCyc8yStocPVW/4t8D13rzZraPfaGuYD\n8wGys7PrH6PdGdQziaevm84tz63i96/l8O8Pt/OrueMZMzAt2qWJiByiqQvK3qrz/I/1Nr8XxrHz\ngEF1ljOArfX2yQaeMLNNwMXAvWZ2QRjHbvcS4+O4c+54Hrgym8K9+zn/nre548WPNGGdiLQ7TXUN\nJdd5PqbetsY/vn9qMTDCzDLNrAswDzho1lJ3z3T3oe4+FHgK+Jq7PxfGsY8aZ2b15d/fPIXPThrI\nva9v4Oy7/sNb63dGuywRkVpNBYE38ryh5UNf7F4FXE9wNtCHwJPuvtrMrjWzmLjDWY20pHjuuHg8\nf7p6Gu7O5x56l+v+tJRVW474ZCwRkVZn7g3/TTezXODbBGFxJ/Cdmk3AHe4+vE0qrCc7O9uXLFkS\njbduFeWV1fzhjVwe+E8upRVVnDKyN985axRjMzR+ICKRY2ZL3T27wW1NBMEjTR3U3b/YCrUdsaM9\nCGoU7avkT4s+5oH/5LKnrJKzx/TjyydlMmlwD5oaOBcRaY5mBUF71VGCoEZxeSUPvJnLows3UVJe\nxfhB3fnxeVlMHtIj2qWJSAeiIDgK7K2o4tllW/j9qzlsKy5n7uQMvjNrFH1TE6Ndmoh0AAqCo0hp\nRRW/e2U9j7y9kbhOxpdnDOPamcM1xbWItEhTQRDOlcXShroldOYH5xzLv791Cmdm9eP3r+Uw887X\neeK9T6g+cHSFtogcHcKZhnqumaWEnv/IzJ4xs0mRLy22DUlP5u7LJvLcf53I4J5dufmZDzj7rjd5\n5cPtHG2tOBFp38JpEdzi7iVmNgOYBTwG3BfZsqTGhEHdefq66dxz+SQqq52rH1vCFQ++y5qtxdEu\nTUQ6iHCCoGZOhHOB+9z97wQT0EkbMTPOHdefl795MrfNOY41+cWce/d/+OZfl/NJYVm0yxORo9xh\nB4vN7J/AFuAMYDKwD3jP3cdHvrxDdfTB4nAUlVVy7xs5PLZwE1XVztlj+3PV9CG6BkFEGtWis4bM\nLAmYDXzg7uvNrD8w1t1fbv1SD09B8KntxeXMfzOXJxdvpqSiiuMGpPKFE4YyZ8IAEuPjol2eiLQj\nLQ2C4UCeu1eY2UxgHPC4u+9p5TrDoiA41N6KKp5ZtoU/vrOJddtL6ZeayNdOHc4l2YMUCCICtDwI\nlhNMFz2UYAK5BQT3MD6ndcsMj4Kgce7O2zmF3PXKOhZv2k2vbl248oShXHnCELonaVhHJJa1NAje\nd/dJZvZdYJ+7321my9x9YiSKPRwFweG5O4tydzH/zQ28traApC5xXD51MF+akcmA7l2jXZ6IREFT\nQRDO5aqVZnYZcCXwmdC6+NYqTlqfmXHC8HROGJ7O2m0l3P/GBh5ZuIlHF27i3HH9uebkYRw3QLOd\nikggnBZBFnAt8I67/8XMMoFL3f32tiiwPrUImidvdxmPvr2JJxZvprSiijOO7cNXTxlO9hCdaSQS\nC1o811DoDmMjQ4tr3b2yFes7IgqClinaV8njCzfx0Nsb2VNWSVb/VC6bOoizx/anV7eEaJcnIhHS\n0jGCmQRXE28iuCnNIOAL7v5mq1YZJgVB6yjbX8Vzy7by+Dub+GhbCXGdjOnD0zlvXH9mH9eftCT1\n/ol0JC0NgqXA5e6+NrQ8EviLu09u9UrDoCBoXe7O2u0l/GPFVv65Mp+PC8voEteJU0f35vwJA5k5\nqjdJXTTzqcjRrqWDxfE1IQDg7uvMTB8XOwgzY3S/VEb3S+U7Z41iZV4Rzy3fwj9WbOWl1dtJjO/E\nqaP6cMHEIBQSOuu6BJGOJpwWwSPAAeCPoVVXAJ11q8qOrar6AO9t2sWLq7bxr5X5FO7dT0piZ844\nti+zjuvHjBG9dI8EkaNIS7uGEoD/AmYQjBG8Cdzr7hWtXWg4FARtr6r6AG/l7ORfK/N5ec12ivZV\nEh9nZA/pydTMnmQP7cGYAWn0SNZFayLtVbODwMw6ASvdfUykijtSCoLoqqw+wJJNu3lt7Q7eztnJ\nmvxiav4LDe6ZxOnH9uGMY/sycXB3jS2ItCPNHiNw9wNmtsLMBrv7J81449nAXUAc8GD9aw/M7Hzg\npwRdT1XAN9z9rSN9H2k78XGdai9WAygur2Tl5iJWby3i3Y27+PO7n/DI25vo3Mk4bmAaM45JZ8Yx\nvZk4uLvmPRJpp8LpGnoVmAK8B+ytWe/ucw7zujhgHXAmkAcsBi5z9zV19ukG7HV3N7NxwJPuPrqp\n46pF0L7traji3Y2FLNm0m3c37mL55j1UH3C6dO7EpMHdOX5YOtOH92Li4O7Ex+lOqSJtpaVnDd3W\nzPedCuS4e26oiCeA84HaIHD30jr7JwO6B+NRLjmhM6eN7stpo/sCUFJeybu5u3h3YyHv5BZy1yvr\n+e2/15OS0JkTj+nFicekc8LwXgzvnawrnEWipNEgMLNjgL7u/ka99ScT3KjmcAYCm+ss5wHTGnif\nC4FfAn0I7oLWUC3XANcADB48OIy3lvYiJTGeM7L6ckZWEAxFZZW8k7uTN9YV8MbaAl5cvQ2AYb2S\nOWdsf6YPT2f8oO4k64wkkTbTaNdQ6M5kP3D3lfXWZwM/cffPNPjCT/ebC8xy9y+Hlj8PTHX3GxrZ\n/2Tgx+5+RlPHVddQx+HufLKrjDfX7+SFD/JZlFvIAYdOBuMHdefkEb2ZPKQHYwam0VNnJIm0SHO7\nhobWDwEAd19iZkPDeN88gukoamQAWxvb2d3fNLPhZtbL3XeGcXw5ypkZQ9KT+Xx6Mp8/fghFZZW8\nv3k3Szft5j85O/ndq+trz0ga1LMrkwb3YFxGd8YOTGPswDS6dtHgs0hraCoIEpvYFs6k9ouBEaHZ\nSrcA84DL6+4Q6n7aEBosngR0AQrDOLZ0QGlJ8Zw6qg+njurDd2aNomhfJau3FPHBliKWfbKHRbmF\n/H158Fmicycja0AqU4b25Phh6Uwb1pPURF3wLtIcTQXBYjP7irs/UHelmV0NLD3cgd29ysyuJ7ir\nWRzwsLuvNrNrQ9vvBz4LXGlmlcA+gumtNWAsAKR1jWf6Mb2Yfkyv2nU7istZmVfEss27WbJpN39c\n9DEPvbWRuE7G5ME9OGlEL6Yfk864DJ2VJBKupsYI+gLPAvv59A9/NsGn9gvdfVubVFiPxgikrvLK\napZv3sN/1hfw+toCVm8tBiCpSxzZQ3ty/LCeTBrcg/EZ3dWVJDGtpVNMnArUXFm82t1fbeX6joiC\nQJqya+9+3s0NTlVduKGQnB3BGcpxnYyRfVOYNLg704alc/ywnvRJaar3U6RjafGNadoTBYEciV17\n97Psk90s37yH5Zv3sOyTPZRWVAEwul8KJx7Ti7ED05g0uAeD05OiXK1I5DTrrKGam9Yf5sCH3Uck\nmnomd+H0Y/ty+rHBdQxV1QdYk1/M2zmFvLmugD8t+piKqgNAcMrqeWP7M2lId7L666wkiR1NjRHs\nA9Y39Vogzd3b9AovtQikNVVWH2BDQSn/WbeTZ5dtYU1+MMYQ18k4tn8KEwf1YFxGGhMH99DVz3JU\na1bXkJkNCePY1e6e15LijpSCQCJpW1E5K/P2sCIv6EZasXkPe/dXAzCsdzLnjOnPlMyejM9Io3uS\nLnKTo4fGCESaqfqAk1tQyqLcQp7/YBvvbgyufgYYmp7EuIzujMtIY/yg7owZoO4kab8UBCKtpKS8\nkg+2FLF88x5Wbi5iRd4e8ovKgU/PTJpxTDqnH9uXCYM09ba0HwoCkQjaUVLOys1FrMzbw9JPdvPe\nxl1UVjtxnYzhvZMZ3S+VUf1SOKZPN4b3TiazVzfiOmmsQdpWi6ahNrNkYF/oJjUjgdHAC+5e2cp1\nihyV+qQkckZWYu0Mq6UVVSzM2cmqLUWs3lrM0o93s2DFp9NspSZ2ZvrwXkwa0p2RfVPIGpCqaxok\nqsK5oGwpcBLQA1gELAHK3P2KyJd3KLUI5GhUUl5JbsFe1u8o5b2NhbydU8iWPftqt/fqlsDYgamM\nzejOuIFpjMtIo0+qwkFaT0tvTGPuXhaaY+hud7/DzJa1bokiHVtKYjzjB3Vn/KDuXDw5A4Dde/ez\ndnsJa7YWs2prEau3FPPGuvW1g9G9unVhZN8UhvVOZkD3rmT0SGJQj64MTU+mh6blllYUVhCY2QnA\nFcDVR/A6EWlCj+QuHD8sneOHpdeuK9tfxZqtxazIK+Kj/GLW7Sjlnyvz2VN2cE9sr24JDOudTL/U\nRAZ078qx/VPI6p/K0F7JmmxPjlg4f9C/AXwfeDY0e+gw4LWIViUSo5K6dCZ7aE+yh/Y8aH1pRRVb\ndu9j864ycneWkrOjlE2FZazI28MLq/KprA6aEfFxxtD0ZDJ7JTMkPYm+qYn0SU1kcM8khqYn6doH\nadARnTVkZp2Abu5eHLmSmqYxApGD7a86QM6OUj7aVsz6HaGQ2LmXj3eVsT80fUaNvqkJjOqXyrBe\nQVjUPAZ076ozmTq4lp419L/AtUA1wXTUaWb2P+5+Z+uWKSLN0aVzJ7IGpJI1IPWg9e5O8b4q8ov3\nsXnXPjbuLOWjbSWs3VbC0k27aq+YBugS14mMnl0Z2L0rfVMTmTtpINMqFkJKf0jpC8l9IF6D1x1V\nOF1DWe5ebGZXAM8D3yMIBAWBSDtmZqQlxZOWFM/ofqlA39pt7k5BSQUbd+4ld+dePi4s4+PCveQX\nlbN++05OG9IZnv/8wQfs0i0IhrQM6JkJ6SOg+yDo1hd6ZEK33m37DUqrCScI4s0sHrgA+L27V5rZ\n0XUVmogcxMzoExo/mFZnsLpWdSUM+g+UbIOSrbB3Z/Ao2Qp7NsOqZ6B8z8GvSe4NvUYGoZDSDxLT\nILkXpA6A1IHBuoSUNvn+5MiEEwR/ADYBK4A3Q5PRRW2MQETaQFw89B8XPBriDmWFULwVSrfDzvWw\nYzUUboCcf8PeHeAHDn1d566Q1BOS0oOWRErfUEj0D4KiW9/ga3IfiNPJiW2lWVNMmFlnd6+KQD2H\npcFikaOAO+wvhdIdULwFivOhdFuwXLYLynYGz0u2BUFCA3+HuvYMWhQJqUHrInUAdB8cBEdanfBI\nSAVND35YLR0sTgN+ApwcWvUG8P+AolarUEQ6FrOgGyghBdKHN71vdWUQBqXboWT7p4FRuiMIjIoS\n2LcLtn0QtDTqi+sSdEslpQfB0a1f0NLo1i8IirSMIDy69YFOmgSwIeG0vR4GVgGXhJY/DzwCXBSp\nokQkhsTFB3+s0zIOv29leTBOUbQlNH6RD3sLgvGLstA4RsG6IEwO1Ou0sE5BYPTIhN4jg+6nLklB\nd1T3IUGLo1ufYFA8xloY4QTBcHf/bJ3l28xseTgHN7PZwF1AHPCgu99eb/sVBGchAZQC17n7inCO\nLSIxKD4Reg4LHk05cCBoRZTkB+MYRZs/DY7CXPjo+WCMo6EuKQw6J0DXHpA2KAiPzl2CgEjuHYRF\nSr+gayq596fdV0dxeIQTBPvMbIa7vwVgZicC+w7zGswsDrgHOBPIAxab2QJ3X1Nnt43AKe6+28zO\nBuYD0470mxAROUinTsEf6ORe0G9sw/u4Q1V5EA67Pw6+lu4IxjaqKoKxjD0fB4+qiqCLam8BePWh\nx+rUORjT6No9+JrSLwiMhJQgJLoPhh5Dg69J6e0uNMIJgmuBx0NjBQC7gS+E8bqpQI675wKY2RPA\n+UBtELj7wjr7LwLCaBuKiLQCM4jvGl4Lo0ZtS2NbaCyjIAiHfbuC4CjfE3zdvhpyX4OK0kODIy4B\nElODFkZCSjAQXnN9RuqAIES69gi2Jfdpk7GNwwZBqKtmvJmlhpaLzewbwMrDvHQgsLnOch5Nf9q/\nGnihoQ1mdg1wDcDgwYMPV7KISGTUbWkw5vD715w9tftj2L0p6KIq3hIExP7S4Gv5Hti8CFZvPXRc\nA8Digi6olL4w6UqY8uVW/qaOYBbRevMLfQv47WFe0lDbp8FzVc3sVIIgmNHIe88n6DYiOztbF7OJ\nyNGh5uypfmOCR1MOHAhaFyX5UFEM5UXBmVQ1p96WbINO8REps7lXbITTwZUHDKqznAFsrb+TmY0D\nHgTOdvfCZtYjInJ069Qp+NSf0vfw+7b2WzfzdeF8Kl8MjDCzTDPrAswDFtTdwcwGA88An3f3dc2s\nRUREWqDRFoGZldDouVV0PdyB3b3KzK4HXiI4ffTh0P0Mrg1tvx/4MZAO3GvBKHpVY1e+iYhIZDRr\niolo0hQTIiJHrqkpJnRPOxGRGKcgEBGJcQoCEZEYpyAQEYlxCgIRkRinIBARiXEKAhGRGKcgEBGJ\ncQoCEZEYpyAQEYlxCgIRkRinIBARiXEKAhGRGKcgEBGJcQoCEZEYpyAQEYlxCgIRkRinIBARiXEK\nAhGRGKcgEBGJcQoCEZEYpyAQEYlxEQ0CM5ttZmvNLMfMbm5g+2gze8fMKszsO5GsRUREGtY5Ugc2\nszjgHuBMIA9YbGYL3H1Nnd12ATcCF0SqDhERaVokWwRTgRx3z3X3/cATwPl1d3D3He6+GKiMYB0i\nItKESAbBQGBzneW80LojZmbXmNkSM1tSUFDQKsWJiEggkkFgDazz5hzI3ee7e7a7Z/fu3buFZYmI\nSF2RDII8YFCd5QxgawTfT0REmiGSQbAYGGFmmWbWBZgHLIjg+4mISDNE7Kwhd68ys+uBl4A44GF3\nX21m14a2329m/YAlQCpwwMy+AWS5e3Gk6hIRkYNFLAgA3P154Pl66+6v83wbQZeRiIhEia4sFhGJ\ncQoCEZEYpyAQEYlxCgIRkRinIBARiXEKAhGRGKcgEBGJcQoCEZEYpyAQEYlxCgIRkRinIBARiXEK\nAhGRGKcgEBGJcQoCEZEYpyAQEYlxCgIRkRinIBARiXEKAhGRGKcgEBGJcQoCEZEYpyAQEYlxCgIR\nkRgX0SAws9lmttbMcszs5ga2m5n9LrR9pZlNimQ9IiJyqIgFgZnFAfcAZwNZwGVmllVvt7OBEaHH\nNcB9kapHREQaFskWwVQgx91z3X0/8ARwfr19zgce98AioLuZ9Y9gTSIiUk/nCB57ILC5znIeMC2M\nfQYC+XV3MrNrCFoMAKVmtvYIa+kF7DzC17Q11dg6VGPrUI0t197qG9LYhkgGgTWwzpuxD+4+H5jf\n7ELMlrh7dnNf3xZUY+tQja1DNbZce6+vrkh2DeUBg+osZwBbm7GPiIhEUCSDYDEwwswyzawLMA9Y\nUG+fBcCVobOHjgeK3D2//oFERCRyItY15O5VZnY98BIQBzzs7qvN7NrQ9vuB54FzgBygDPhihMpp\ndrdSG1KNrUM1tg7V2HLtvb5a5n5Il7yIiMQQXVksIhLjFAQiIjGuwwfB4aa5iAYzG2Rmr5nZh2a2\n2sy+Hlrf08z+z8zWh772iHKdcWa2zMz+2U7r625mT5nZR6Gf5QntsMZvhv6NV5nZX8wsMdo1mtnD\nZrbDzFbVWddoTWb2/dDvz1ozmxXFGu8M/VuvNLNnzax7e6uxzrbvmJmbWa9o1hiuDh0EYU5zEQ1V\nwLfd/VjgeOC/QnXdDLzi7iOAV0LL0fR14MM6y+2tvruAF919NDCeoNZ2U6OZDQRuBLLdfQzBSRPz\n2kGNjwKz661rsKbQ/8t5wHGh19wb+r2KRo3/B4xx93HAOuD77bBGzGwQcCbwSZ110aoxLB06CAhv\nmos25+757v5+6HkJwR+wgQS1PRba7THggqgUCJhZBnAu8GCd1e2pvlTgZOAhAHff7+57aEc1hnQG\nuppZZyCJ4DqZqNbo7m8Cu+qtbqym84En3L3C3TcSnOE3NRo1uvvL7l4VWlxEcN1Ru6ox5DfAdzn4\n4tio1Biujh4EjU1h0W6Y2VBgIvAu0LfmOorQ1z5RLO23BP+ZD9RZ157qGwYUAI+Euq8eNLPk9lSj\nu28BfkXwyTCf4DqZl9tTjXU0VlN7/R36EvBC6Hm7qdHM5gBb3H1FvU3tpsaGdPQgCGsKi2gxs27A\n08A33L042vXUMLPzgB3uvjTatTShMzAJuM/dJwJ7iX5X1UFC/eznA5nAACDZzD4X3aqOWLv7HTKz\nHxJ0r/65ZlUDu7V5jWaWBPwQ+HFDmxtY127+FnX0IGi3U1iYWTxBCPzZ3Z8Jrd5eM/tq6OuOKJV3\nIjDHzDYRdKedZmZ/akf1QfBvm+fu74aWnyIIhvZU4xnARncvcPdK4BlgejursUZjNbWr3yEz+wJw\nHnCFf3oRVHupcThB6K8I/e5kAO+bWT/aT40N6uhBEM40F23OzIygb/tDd/+fOpsWAF8IPf8C8Pe2\nrg3A3b/v7hnuPpTgZ/aqu3+uvdQH4O7bgM1mNiq06nRgDe2oRoIuoePNLCn0b346wXhQe6qxRmM1\nLQDmmVmCmWUS3DvkvSjUh5nNBr4HzHH3sjqb2kWN7v6Bu/dx96Gh3508YFLo/2q7qLFR7t6hHwRT\nWKwDNgA/jHY9oZpmEDQLVwLLQ49zgHSCMzbWh772bAe1zgT+GXreruoDJgBLQj/H54Ae7bDG24CP\ngFXAH4GEaNcI/IVgzKKS4I/V1U3VRNDdsQFYC5wdxRpzCPrZa35n7m9vNdbbvgnoFc0aw31oigkR\nkRjX0buGRETkMBQEIiIxTkEgIhLjFAQiIjFOQSAiEuMUBCL1mFm1mS2v82i1K5bNbGhDs1WKRFPE\nblUpchTb5+4Tol2ESFtRi0AkTGa2ycz+28zeCz2OCa0fYmavhObJf8XMBofW9w3Nm78i9JgeOlSc\nmT0Quk/By2bWNWrflAgKApGGdK3XNXRpnW3F7j4V+D3BDK2Enj/uwTz5fwZ+F1r/O+ANdx9PMA/S\n6tD6EcA97n4csAf4bES/G5HD0JXFIvWYWam7d2tg/SbgNHfPDU0auM3d081sJ9Df3StD6/PdvZeZ\nFQAZ7l5R5xhDgf/z4AYwmNn3gHh3/1kbfGsiDVKLQOTIeCPPG9unIRV1nlejsTqJMgWByJG5tM7X\nd0LPFxLM0gpwBfBW6PkrwHVQe//n1LYqUuRI6JOIyKG6mtnyOssvunvNKaQJZvYuwYeoy0LrbgQe\nNrObCO6a9sXQ+q8D883saoJP/tcRzFYp0q5ojEAkTKExgmx33xntWkRak7qGRERinFoEIiIxTi0C\nEZEYpyAQEYlxCgIRkRinIBARiXEKAhGRGPf/AfiS0bC1YvhDAAAAAElFTkSuQmCC\n",
            "text/plain": [
              "\u003cFigure size 600x400 with 1 Axes\u003e"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "plt.plot(epochs, losses, label='Pre-training')\n",
        "plt.plot(more_epochs, more_losses, label='On device')\n",
        "plt.ylim([0, max(plt.ylim())])\n",
        "plt.xlabel('Epoch')\n",
        "plt.ylabel('Loss [Cross Entropy]')\n",
        "plt.legend();"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Jbe9_LjAbEMF"
      },
      "source": [
        "Above you can see that the on-device training picks up exactly where the pretraining stopped."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UDIi0_RlPb2n"
      },
      "source": [
        "## Save the trained weights\n",
        "\n",
        "When you complete a training run on a device, the model updates the set of weights it is using in memory. Using the `save` signature method you created in your TensorFlow Lite model, you can save these weights to a checkpoint file for later reuse and improve your model."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7c3d3cc5f171"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'checkpoint_path': array(b'/tmp/model.ckpt', dtype=object)}"
            ]
          },
          "execution_count": 36,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "save = interpreter.get_signature_runner(\"save\")\n",
        "\n",
        "save(checkpoint_path=np.array(\"/tmp/model.ckpt\", dtype=np.string_))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vvlZN-rhR_Ag"
      },
      "source": [
        "In your Android application, you can store the generated weights as a checkpoint file in the internal storage space allocated for your app.\n",
        "\n",
        "```Java\n",
        "try (Interpreter interpreter = new Interpreter(modelBuffer)) {\n",
        "    // Conduct the training jobs.\n",
        "\n",
        "    // Export the trained weights as a checkpoint file.\n",
        "    File outputFile = new File(getFilesDir(), \"checkpoint.ckpt\");\n",
        "    Map\u003cString, Object\u003e inputs = new HashMap\u003c\u003e();\n",
        "    inputs.put(\"checkpoint_path\", outputFile.getAbsolutePath());\n",
        "    Map\u003cString, Object\u003e outputs = new HashMap\u003c\u003e();\n",
        "    interpreter.runSignature(inputs, outputs, \"save\");\n",
        "}\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SSDydMyOQfL5"
      },
      "source": [
        "## Restore the trained weights\n",
        "\n",
        "Any time you create an interpreter from a TFLite model, the interpreter will initially load the original model weights.\n",
        "\n",
        "So after you've done some training and saved a checkpoint file, you'll need to run the `restore` signature method to load the checkpoint.\n",
        "\n",
        "A good rule is \"Anytime you create an Interpreter for a model, if the checkpoint exists, load it\". If you need to reset the model to the baseline behavior, just delete the checkpoint and create a fresh interpreter.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5yIZoLveRZgp"
      },
      "outputs": [],
      "source": [
        "another_interpreter = tf.lite.Interpreter(model_content=tflite_model)\n",
        "another_interpreter.allocate_tensors()\n",
        "\n",
        "infer = another_interpreter.get_signature_runner(\"infer\")\n",
        "restore = another_interpreter.get_signature_runner(\"restore\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fjiUbx7zIoLq"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\nsm1z0KBBLF68uGzbq6b+/fszYsQIdtxxx7xLMbNers8HQFtbGwMHDqSuro6i2+VukzVr1jBwYFf3\n++q9IoJVq1bR1tbGyJEj8y7HzHq5Pj8FtHbtWgYPHly2F/++TBKDBw8u69GQmW2/+nwAAH7xL+Kf\nhZmVarsIADMz67k+fw6go7pp95Z1e62XndBtm5qaGg499FAigpqaGqZPn87RRx+9xedcddVVXHPN\nNYwZM4Zbb721XOWaWV/SNKj7NpvavlP27re7AMjDgAEDWLBgAQAPPPAAF154IY888sgWn3P11Vdz\n3333lXyydt26dfTr51+XmZWPp4DKbPXq1ey+++6bli+//HLGjh3LqFGjuPjiiwH47ne/y0svvcSk\nSZO44oorePPNN/nyl7/MqFGjOPLII3n66acBaGpqYurUqUycOJEpU6awYsUKTj75ZMaOHcvYsWN5\n7LHHchmjmW0fvEtZBu+99x719fWsXbuW119/nTlz5gAwe/ZslixZwh//+EcigkmTJjF37lyuvfZa\n7r//fh5++GGGDBnCWWedxejRo7nrrruYM2cOU6ZM2XREMX/+fB599FEGDBjAqaeeynnnnce4ceN4\n9dVXOfbYY/vs+xXMLH8OgDIongJ6/PHHmTJlCosWLWL27NnMnj2b0aNHA9De3s6SJUsYP378Zs9/\n9NFHueOOOwD47Gc/y6pVq3jnncJ836RJkxgwYAAADz74IM8+++ym561evbrPvmfBzPLnACizo446\nipUrV7JixQoiggsvvJDvfOc7W3xOZ5/LvPFyzuJb1W7YsIHHH398UyCYWe/TkwtRWvtXsJAS+BxA\nmT333HOsX7+ewYMHc+yxx3LDDTfQ3t4OwLJly1i+fPlHnjN+/PhNVwK1tLQwZMgQdt1114+0mzhx\nItOnT9+0vPGow8xsa1T8CEDSDcCJwPKIOCRb1wR8G1iRNbsoImaVo79SLtvsTk+nVTaeA4DC3vyM\nGTOoqalh4sSJLF68mKOOOgqA2tpabrnlFvbaa6/Nnt/U1MS3vvUtRo0axc4778yMGTM67eeqq67i\ne9/7HqNGjWLdunWMHz+ea6+9dusGaWbJq8YU0E3AdODmDuuviIifVaH/ilu/fn2Xj51zzjmcc845\nH1nf2tq66fs99tiDu++++yNtmpqaNlseMmQIv/nNb7a6TjOzYhWfAoqIucCble7HzMx6Rp2dgCx7\n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\nX3BIcuP5vEYAAAAASUVORK5CYII=\n",
            "text/plain": [
              "\u003cFigure size 600x400 with 1 Axes\u003e"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "logits_before = infer(x=train_images[:1])['logits'][0]\n",
        "\n",
        "# Restore the trained weights from /tmp/model.ckpt\n",
        "restore(checkpoint_path=np.array(\"/tmp/model.ckpt\", dtype=np.string_))\n",
        "\n",
        "logits_after = infer(x=train_images[:1])['logits'][0]\n",
        "\n",
        "compare_logits({'Before': logits_before, 'After': logits_after})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "X7T6pja2bPqV"
      },
      "source": [
        "The checkpoint was generated by training and saving with TFLite. Above you can see that applying the checkpoint updates the behavior of the model."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cAo-3Eg7oGH7"
      },
      "source": [
        "Note: Loading the saved weights from the checkpoint can take time, based on the number of variables in the model and the size of the checkpoint file.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v9I_-gjdSnGn"
      },
      "source": [
        "In your Android app, you can restore the serialized, trained weights from the checkpoint file you stored earlier.\n",
        "\n",
        "```Java\n",
        "try (Interpreter anotherInterpreter = new Interpreter(modelBuffer)) {\n",
        "    // Load the trained weights from the checkpoint file.\n",
        "    File outputFile = new File(getFilesDir(), \"checkpoint.ckpt\");\n",
        "    Map\u003cString, Object\u003e inputs = new HashMap\u003c\u003e();\n",
        "    inputs.put(\"checkpoint_path\", outputFile.getAbsolutePath());\n",
        "    Map\u003cString, Object\u003e outputs = new HashMap\u003c\u003e();\n",
        "    anotherInterpreter.runSignature(inputs, outputs, \"restore\");\n",
        "}\n",
        "```\n",
        "\n",
        "Note: When your application restarts, you should reload your trained weights prior to running new inferences."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zjcrv57DSkz2"
      },
      "source": [
        "## Run Inference using trained weights\n",
        "\n",
        "Once you have loaded previously saved weights from a checkpoint file, running the `infer` method uses those weights with your original model to improve predictions. After loading the saved weights, you can use the `infer` signature method as shown below.\n",
        "\n",
        "Note: Loading the saved weights is not required to run an inference, but running in that configuration produces predictions using the originally trained model, without improvements."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_ROmlpHWS0nX"
      },
      "outputs": [],
      "source": [
        "infer = another_interpreter.get_signature_runner(\"infer\")\n",
        "result = infer(x=test_images)\n",
        "predictions = np.argmax(result[\"output\"], axis=1)\n",
        "\n",
        "true_labels = np.argmax(test_labels, axis=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "x6nHopKlAD6-"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(10000, 10)"
            ]
          },
          "execution_count": 40,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "result['output'].shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fGPtqeVULZui"
      },
      "source": [
        "Plot the predicted labels."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GHbRasdfasd4"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\nEEKUiiY9QgghhMgFmvQIIYQQIhdo0iOEEEKIXKBJjxBCCCFygSY9QgghhMgFtarT0759+6Rnz571\ndCh1Y9GiRcH+5JNPom3t2rUL9tdffx1ss7jI7/Lly4PdqdOqlQzatGlTtuOsKwsWLEBVVVVaVeI6\nU4l9mQcmTZpUlSRJh3LvV/3Z8ORpbH722WfB3mCDDdZ6f3yvbtmyZUbLhqM+xmYl9iVTVVUVvf7y\ny5oXQV9nndg/sv76qxZub9u2bdmPa23J6staTXp69uyJiRMnlueoysRPf7pq4dYZM2ZE244//vhg\nf/jhh8Fed934Z48aNSrYvL+DDy6tlhpPqIDVL5C1YdiwYWXbF1OJfZkHzKxeCl6qPxue5j42v/pq\n1eo7CxYsCPZWW21V688DQIsWq4r68r26f//+UTv/R2lDUR9js1L6Mo2//OUv0esVK1YEmydArVu3\njtptscUWwT788MPr5+DWgqy+lLwlhBBCiFzQJJaheOaZZ6LXI0eODDa7Wt97772o3VlnnRVs/iuj\nVatWUbudd9452HfffXewH3rooajd7373u2CzdFZOz44QQlQCX3zxRbA5jCDL08MV/vme63nrrbeC\nPWDAgLoeYrPEr5KQ5vny7dgzs95660Xb2OvGSoeXKtO+y7/P8uQBBxwQ7NGjR9f4eX98Xm1pSPS0\nFkIIIUQu0KRHCCGEELlAkx4hhBBC5IKKiel55ZVXotdXXnllsOfOnRttGzhwYLDnzJkTbJ/62L59\n+2Bzap7PFuCU9Sy98+yzzw527969g3366adH7Tp27AghhGjKbLjhhsH+61//Gmyfojx48OBgZ2Ve\nPfjgg8H+05/+FOz9999/LY6y+ZEV08OZwj6W1MfxMGeeeWaw+bnWuXPnqB2non/66afB/vzzz6N2\nG2+8cbCnTp2a+r0MP1uzMvvqG3l6hBBCCJELNOkRQgghRC6od3kry411ww03BPvFF1+M2m200UbB\n3nHHHaNtXCiJXXAvv/xy1I7lLpac/DG99NJLwf7BD34Q7E033TRq9/777wf77bffDvZpp50Wtbvx\nxhuDzRWegWz3pBBCVAqcsj527Nhg8/0SiMMNTjrppGBfeumlUTu+V/sQA7EK/1zgfsiSsB599NFg\n//73v4+2vf7668HmcitejuzatWuwuayAf2by51iO83LZ+eefH2wOD2lIOcujp64QQgghcoEmPUII\n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\n6jpOAAAAAElFTkSuQmCC\n",
            "text/plain": [
              "\u003cFigure size 1000x1000 with 25 Axes\u003e"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',\n",
        "               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']\n",
        "\n",
        "def plot(images, predictions, true_labels):\n",
        "  plt.figure(figsize=(10,10))\n",
        "  for i in range(25):\n",
        "      plt.subplot(5,5,i+1)\n",
        "      plt.xticks([])\n",
        "      plt.yticks([])\n",
        "      plt.grid(False)\n",
        "      plt.imshow(images[i], cmap=plt.cm.binary)\n",
        "      color = 'b' if predictions[i] == true_labels[i] else 'r'\n",
        "      plt.xlabel(class_names[predictions[i]], color=color)\n",
        "  plt.show()\n",
        "\n",
        "plot(test_images, predictions, true_labels)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Dm8BxJOm_4rG"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(10000,)"
            ]
          },
          "execution_count": 42,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "predictions.shape"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eijDL3jNS6WI"
      },
      "source": [
        "In your Android application, after restoring the trained weights, run the inferences based on the loaded data.\n",
        "\n",
        "```Java\n",
        "try (Interpreter anotherInterpreter = new Interpreter(modelBuffer)) {\n",
        "    // Restore the weights from the checkpoint file.\n",
        "\n",
        "    int NUM_TESTS = 10;\n",
        "    FloatBuffer testImages = FloatBuffer.allocateDirect(NUM_TESTS * 28 * 28).order(ByteOrder.nativeOrder());\n",
        "    FloatBuffer output = FloatBuffer.allocateDirect(NUM_TESTS * 10).order(ByteOrder.nativeOrder());\n",
        "\n",
        "    // Fill the test data.\n",
        "\n",
        "    // Run the inference.\n",
        "    Map\u003cString, Object\u003e inputs = new HashMap\u003c\u003e();\n",
        "    inputs.put(\"x\", testImages.rewind());\n",
        "    Map\u003cString, Object\u003e outputs = new HashMap\u003c\u003e();\n",
        "    outputs.put(\"output\", output);\n",
        "    anotherInterpreter.runSignature(inputs, outputs, \"infer\");\n",
        "    output.rewind();\n",
        "\n",
        "    // Process the result to get the final category values.\n",
        "    int[] testLabels = new int[NUM_TESTS];\n",
        "    for (int i = 0; i \u003c NUM_TESTS; ++i) {\n",
        "        int index = 0;\n",
        "        for (int j = 1; j \u003c 10; ++j) {\n",
        "            if (output.get(i * 10 + index) \u003c output.get(i * 10 + j)) index = testLabels[j];\n",
        "        }\n",
        "        testLabels[i] = index;\n",
        "    }\n",
        "}\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cznoIDphGPEg"
      },
      "source": [
        "Congratulations! You now have built a TensorFlow Lite model that supports on-device training. For more coding details, check out the example implementation in the [model personalization demo app](https://github.com/tensorflow/examples/tree/master/lite/examples/model_personalization).\n",
        "\n",
        "If you are interested in learning more about image classification, check [Keras classification tutorial](https://www.tensorflow.org/tutorials/keras/classification) in the TensorFlow official guide page. This tutorial is based on that exercise and provides more depth on the subject of classification.\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "overview.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
